use crate::core::base;
use crate::std_::StdFunc;
use crate::core::model::data::Data;
use std::collections::HashMap;

// 变量 ------------------------------------------------

/// 获取变量
pub fn get_var(yuzu: &str, name: &str) -> Option<Data> {
    if let Some(map) = base::yuzu_var().get(yuzu) {
        if let Some(data) = map.get(name) {
            return Some(data.clone());
        }
    }
    None
}

/// 获取变量 如果没找到则一定意料外 直接报错退出
pub fn get_var_exist(yuzu: &str, var: &str) -> Data {
    match get_var(yuzu, var) {
        None => {
            base::log().err_exit(format!("not find this var : `{}`", var));
        }
        Some(data) => { data }
    }
}

/// 判断变量是否存在
pub fn var_is_exist(yuzu: &str, name: &str) -> bool {
    if let Some(map) = base::yuzu_var().get(yuzu) {
        if map.contains_key(name) { return true; }
    }
    false
}

/// 设置变量
pub fn set_var(yuzu: &str, name: &str, data: Data) -> String {
    let mut yuzu_var = base::yuzu_var();
    let map = match yuzu_var.get_mut(yuzu) {
        None => {
            yuzu_var.insert(yuzu.to_string(), HashMap::new());
            yuzu_var.get_mut(yuzu).unwrap()
        }
        Some(yuzu) => { yuzu }
    };
    let data_type = data.get_type_name();
    map.insert(name.to_string(), data);
    data_type
}

/// 删除变量
pub fn delete_var(yuzu: &str, name: &str) {
    if let Some(map) = base::yuzu_var().get_mut(yuzu) {
        map.remove(name);
    }
}

/// 删除yuzu
pub fn delete_yuzu(yuzu: &str) {
    base::yuzu_var().remove(yuzu);
}

// 引用 --------------------------------------------------------------------------

/// 设置引用 如果 data 不存在则直接报错
pub fn set_ref(data_yuzu: &str, data_name: &str, ref_yuzu: &str, ref_name: &str) {
    // exist
    if !var_is_exist(data_yuzu, data_name) {
        base::log().err_exit(format!("[{}]-> `{}` do not exist", data_yuzu, data_name));
    }
    // ref
    let mut yuzu_ref_map = base::yuzu_ref();
    let ref_map = match yuzu_ref_map.get_mut(ref_yuzu) {
        Some(map) => { map }
        None => {
            let map = HashMap::<String, (String, String)>::new();
            yuzu_ref_map.insert(ref_yuzu.to_string(), map);
            yuzu_ref_map.get_mut(ref_yuzu).unwrap()
        }
    };
    ref_map.insert(ref_name.to_string(), (data_yuzu.to_string(), data_name.to_string()));
}

/// 获取引用所关联的变量的信息
pub fn get_var_info_from_ref(ref_yuzu: &str, ref_name: &str) -> Option<(String, String)> {
    let yuzu_ref_map = base::yuzu_ref();
    let ref_map = match yuzu_ref_map.get(ref_yuzu) {
        None => { return None; }
        Some(ref_map) => { ref_map }
    };
    ref_map.get(ref_name).map(|(a, b)| (a.clone(), b.clone()))
}

/// 获取引用所关联的data
pub fn get_data_from_ref(ref_yuzu: &str, ref_name: &str) -> Option<Data> {
    match get_var_info_from_ref(ref_yuzu, ref_name) {
        None => { None }
        Some((data_yuzu, data_name)) => {
            match get_var(&data_yuzu, &data_name) {
                None => {
                    delete_ref(ref_yuzu, ref_name);
                    None
                }
                Some(data) => { Some(data) }
            }
        }
    }
}

/// 删除引用
pub fn delete_ref(ref_yuzu: &str, ref_name: &str) {
    if let Some(ref_map) = base::yuzu_ref().get_mut(ref_yuzu) {
        ref_map.remove(ref_name);
    }
}

// 方法 --------------------------------------

/// 获取方法
pub fn get_func(func_name: &str) -> &StdFunc {
    match base::STD_FUNC.get(func_name) {
        Some(func) => { func }
        None => {
            //todo do not support find other function
            base::log().err_exit(format!("std func can not fund : {}\n
            and do not support find other function right now", func_name));
        }
    }
}

